<?php
namespace app\framework\lib;
use Curl\Curl;
use think\Exception;

class HttpClient
{
    public static $client = null;
    public static $host = "";
    public static $instance =null;

    public static function getInstance()
    {
        if (is_null(self::$instance)) {
            self::$client = new Curl();
            self::$instance = new self();
        }
        return self::$instance;
    }
    public function init($service)
    {
        $connect_timeout = 3000;
        $query_timeout = 4000;
        $rpc= Config::getInstance()->rpc;
        $config = $rpc["{$service}"];
        if (!empty($config['connect_timeout'])) {
            $connect_timeout = $config['connect_timeout'];
        }
        if (!empty($config['query_timeout'])) {
            $query_timeout = $config['query_timeout'];
        }
        self::$host = $config["host"];
        self::$client->setOpt(CURLOPT_NOSIGNAL, true);
        //禁止文件的信息作为数据流输出，否则响应header也会数出来
        self::$client->setOpt(CURLOPT_HEADER, false);
        //则会跟踪爬取重定向页面，否则，不会跟踪重定向页面
        self::$client->setOpt(CURLOPT_FOLLOWLOCATION, true);
        self::$client->setOpt(CURLOPT_CONNECTTIMEOUT_MS, $connect_timeout);
        self::$client->setOpt(CURLOPT_TIMEOUT_MS, $query_timeout);
        self::$client->setOpt(CURLOPT_TCP_KEEPALIVE, true);
        self::$client->setOpt(CURLOPT_TCP_KEEPIDLE, 60);
        self::$client->setOpt(CURLOPT_TCP_KEEPINTVL, 15);
        if (isset($config['ssl'])) {
            $ssl = $config['ssl'];
            if ($ssl == 0) {
                //禁止https协议验证ssl安全认证证书
                self::$client->setOpt(CURLOPT_SSL_VERIFYPEER, false);
                //禁止https协议验证域名
                self::$client->setOpt(CURLOPT_SSL_VERIFYHOST, 0);
            } elseif ($ssl == 1) {
                self::$client->setOpt(CURLOPT_SSL_VERIFYPEER, false);
                self::$client->setOpt(CURLOPT_SSL_VERIFYHOST, 1);
            } elseif ($ssl == 2) {
                self::$client->setOpt(CURLOPT_SSL_VERIFYPEER, true);
                self::$client->setOpt(CURLOPT_CAINFO, getcwd() . '/../../cacert.pem');
            }
        }
    }

    /**
     * 设置请求头
     * @param $data
     * @return $this
     */
    public function setHeader($data = [])
    {
        foreach ($data as $key => $val) {
            self::$client->setHeader($key, $val);
        }
        return $this;
    }

    /**
     * @param $ip
     * @return $this
     */
    public function setProxy($ip,$username="",$passwd="")
    {
        self::$client->setOpt(CURLOPT_PROXY, $ip);
        if (!empty($username) && !empty($password)) {
            self::$client->setOpt(CURLOPT_PROXYAUTH, CURLAUTH_BASIC);
            self::$client->setOpt(CURLOPT_PROXYUSERPWD, "{$username}:{$passwd}");
        }
        return $this;
    }


    /**
     * 设置cookie
     * @param $data
     * @return $this
     */
    public function setCookie($data = [])
    {
        foreach ($data as $key => $val) {
            self::$client->setCookie($key, $val);
        }
        return $this;
    }

    /**
     * ssl加密套件设置
     * @param $val
     * @return $this
     */
    public function setCipher($val="AES128, AES256, AES")
    {
        self::$client->setOpt(CURLOPT_SSL_CIPHER_LIST,$val);
        return $this;
    }

    public function request($url, $method, $data)
    {
        $log =$data;
        if (!empty(self::$host) && substr($url, 0, 4) != "http") {
            $url = self::$host . $url;
        }
        $start_time = microtime(true);
        $log["data"]=$data;
        $log["url"]= $url;
        switch (strtoupper($method)) {
            case "GET":
                self::$client->get($url, $data);
                break;
            case "POST":
                self::$client->post($url, $data);
                break;
            case "PUT":
                self::$client->put($url, $data, true);
                break;
            case "DELETE":
                self::$client->delete($url, $data, true);
                break;
            case "PATCH":
                self::$client->patch($url, $data);
                break;
            default:
                if (isset($data['_fileField']) && isset($data['file'])) {
                    $data[$data['_fileField']] = new \CURLFile(realpath($data['file']));
                    unset($data['_fileField']);
                    unset($data['file']);
                }
                self::$client->setOpt(CURLOPT_URL, $url);
                self::$client->setOpt(CURLOPT_POST, true);
                self::$client->setOpt(CURLOPT_POSTFIELDS, $data);
                self::$client->exec();
                break;
        }
        $costTime = round(microtime(true) - $start_time, 3);
        $response = self::$client->response;
        $log["cost_time"] = $costTime;
        $log["res"] = $response;
        Log::curl("data={post}", $log);
        if (self::$client->http_status_code!=200) {
            unset($log["res"]);
            $log["message"] = self::$client->error_message;
            Log::error("data={post}", ["post" => $log]);
            throw new Exception(self::$client->error_message);
        }
        if (!$response && self::$client->isServerError()) {
            unset($log["res"]);
            Log::error("data={post}", ["post" =>$log]);
            throw new Exception(self::$client->curl_error_message);
        }
        $resultArray = json_decode($response, true);
        if (!is_array($resultArray)) {
            Log::error("解析接口返回值错误");
            throw new Exception("调用接口错误");
        }
        return $resultArray;
    }
}